On 22 May 1996, Philip Guenther wrote: > The race condition in find should be eliminatible by using fchdir() > and passing the '-exec'ed command a simple filename. You have to keep > open one descriptor for each level descended which should max out at > MAXPATHLEN/2. That should be within the bounds of modern UNIX systems. Yes, the race condition in find can be eliminated, but your pseudocode does not do it. > cur = open argv[1]; > fchdir(cur); > do_dir(cur); > > do_dir(int cur) { > foreach file in "." { > int fd = open file; > do_stuff_from_command_line; > if ISDIR(fstat fd) { > fchdir(fd); > do_dir(fd); > fchdir(cur); > } > } > } The problem is with int fd = open file; How can you be sure that you're not opening a symlink? When you fstat it later it will certainly not be a symlink. Here's a bit of perl I wrote earlier today which does eliminate the race condition: #!/opt/bin/perl require 'sys/syscall.ph'; require 'stat.pl'; open(DIR, "<$ARGV[0]") || die "can't open $ARGV[0]: $!"; ($dev1, $ino1) = (stat DIR)[$ST_DEV, $ST_INO]; #sleep 20; ($dev2, $ino2) = (lstat $ARGV[0])[$ST_DEV, $ST_INO]; if ($dev2 != $dev1 || $ino2 != $ino1) { print "lost race!\n"; } elsif (-l _) { print "is a symlink\n"; } else { syscall(&SYS_fchdir, fileno(DIR)) == 0 || die "can't fchdir: $!"; print "chdir suceeded\n"; system "/bin/pwd"; } The script opens a handle to the directory and notes its device and inode. It then lstats the directory name, and checks that it hasn't been fooled into opening a symlink. The commented out `sleep 20;' line gave me enough time to replace a directory with a symlink to /etc. It would be nice if one could call fchdir(2) directly from perl, without having to go through syscall(). Sean. -- Sean Vickery <S.Vickery@its.gu.edu.au> Ph: +61 (0)7 3875 6410 Systems Programmer Information Services Griffith University